/*
 * Created on 2004-04-20
 */
package org.opencube.data;

import java.io.Serializable;
import java.util.Properties;

/**
 * <p>The <code>DataSource</code> provides a data manipulation interface.
 * <p>However it abstracts from the data persistence storage, you'll find here 
 * a similarity to the JDBC interface.
 * 
 * @author <a href="mailto:maciek@fingo.pl">FINGO - Maciej Mroczko</a>
 */
public abstract class DataSource implements Serializable
{
	/**
	 * The database property constant: data source user name = 'username'
	 */
	public static final String PROPERTY_USERNAME = "ds_username";
	 
	/**
	 * The database property constant: data source password = 'password'
	 */
	public static final String PROPERTY_PASSWORD = "ds_password";

	/**
	 * The database property constant: data source url = 'ds_url'
	 */
	public static final String PROPERTY_URL = "ds_url";
	
	/**
	 * The database property constant: database type = 'db_type'
	 */
	public static final String PROPERTY_DATABASE_TYPE= "db_type";

	/**
	 * The paramater type constant: string = 'string'.
	 */
	public static final String TYPE_STRING = "string";
	
	/**
	 * The paramater type constant: int = 'int'.
	 */
	public static final String TYPE_INTEGER = "int";

	/**
	 * The paramater type constant: bool = 'bool'.
	 */
	public static final String TYPE_BOOLEAN = "bool";

	/**
	 * The paramater type constant: cursor = 'cursor'.
	 */
	public static final String TYPE_CURSOR = "cursor";

	/**
	 * The paramater type constant: blob = 'blob'.
	 */
	public static final String TYPE_BLOB = "blob";

	/**
	 * The paramater type constant: clob = 'clob'.
	 */
	public static final String TYPE_CLOB = "clob";

	/**
	 * All allowed types for the parameters
	 */
	public static final String[] ALLOWED_TYPES = new String[]
	{
		TYPE_BOOLEAN,
		TYPE_CURSOR,
		TYPE_INTEGER,
		TYPE_STRING,
		TYPE_BLOB,
		TYPE_CLOB,
	};
	/**
	 * The data source properties
	 */
	protected Properties properties = null;
	
	/**
	 * The data source url
	 */
	protected String url = null;

	/**
	 * The data source username
	 */
	protected String username = null;
	
	/**
	 * The data source password
	 */
	protected String password = null;
	
	/**
	 * The data source imlementation type
	 */
	protected String dataSourceType = null;
	
	/**
	 * Enables / desables using batching when supported
	 */
	protected boolean useBatchingWhenSupported = true;
	
	/**
	 * Connects to data source with the given properties set.
	 *  
	 * @param properties
	 * 
	 * @throws Exception
	 */
	public void connect( Properties properties ) throws Exception
	{
		this.properties = properties;
		
		this.url = properties.getProperty( PROPERTY_URL );
		this.username = properties.getProperty( PROPERTY_USERNAME );
		this.password = properties.getProperty( PROPERTY_PASSWORD );
		this.dataSourceType = properties.getProperty( PROPERTY_DATABASE_TYPE );
	}
	
	/**
	 * Binds the given variables and executes the statement
	 * 
	 * @param statement statement to call
	 * @param bindVariables variables to bind: { param_name->value } pairs
	 * 
	 * @return The disconnected call result containing any record sets and 
	 * filled bound bariables 
	 * 
	 * @throws Exception
	 * @see CallResult
	 */
	public abstract CallResult executeCall( String statement, BoundVariable[] bindVariables ) throws Exception;

	/**
	 * Binds the given variables and executes the statement
	 * 
	 * @param statement statement to call
	 * @param bindVariables variables to bind: { param_name->value } pairs
	 * 
	 * @return The disconnected call result containing any record sets and 
	 * filled bound bariables 
	 * 
	 * @throws Exception
	 * @see CallResult
	 */
	public abstract CallResult executeCall( String statement, BoundVariable[] bindVariables, String namespace, String resourceKey ) throws Exception;

	/**
	 * Executes the given query statement
	 * 
	 * @param query query statement to execute
	 * 
	 * @return The disconnected record set
	 * 
	 * @throws Exception
	 * @see RecordSet
	 */
	public abstract RecordSet executeQuery( String query ) throws Exception;

	/**
	 * Executes the given query statement
	 * 
	 * @param query query statement to execute
	 * 
	 * @return The disconnected record set
	 * 
	 * @throws Exception
	 * @see RecordSet
	 */
	public abstract RecordSet executeQuery( String query, String namespace, String resourceKey ) throws Exception;

	/**
	 * Executes the given SQL
	 *  
	 * @param statement the statement to execute
	 *   
	 * @return The execution result
	 * 
	 * @throws Exception
	 */
	public abstract boolean execute( String statement ) throws Exception;

	/**
	 * Executes the given SQL
	 *  
	 * @param statement the statement to execute
	 *   
	 * @return The execution result
	 * 
	 * @throws Exception
	 */
	public abstract boolean execute( String statement, String namespace, String resourceKey ) throws Exception;

	/**
	 * Executes the given update statement
	 * 
	 * @param statement the update statement to execute
	 * 
	 * @return The number of affected records
	 * 
	 * @throws Exception
	 */
	public abstract int executeUpdate( String statement ) throws Exception;
	
	/**
	 * Executes the given update statement
	 * 
	 * @param statement the update statement to execute
	 * 
	 * @return The number of affected records
	 * 
	 * @throws Exception
	 */
	public abstract int executeUpdate( String statement, String namespace, String resourceKey ) throws Exception;

	/**
	 * Executes the statement in the batch mode.
	 *  
	 * @param statement  the update statement to execute
	 * @param vars the array [ updatesCount ][ variablesPerUpdate ] of variables to bound
	 * 
	 * @return The number of the affected records
	 * 
	 * @throws Exception
	 */
	public abstract int executeBatch( String statement, BoundVariable[][] vars ) throws Exception;
	
	/**
	 * Executes the statement in the batch mode.
	 *  
	 * @param statement  the update statement to execute
	 * @param vars the array [ updatesCount ][ variablesPerUpdate ] of variables to bound
	 * 
	 * @return The number of the affected records
	 * 
	 * @throws Exception
	 */
	public abstract int executeBatch( String statement, BoundVariable[][] vars, String namespace, String resourceKey ) throws Exception;

	/**
	 * Gets the minimum size of the batch, for which the batching makes sense 
	 * from the performance point of view.
	 * 
	 * @return The minimum batch size
	 * 
	 * @throws Exception
	 */
	public abstract int getMinimumBatchSize() throws Exception;
	
	/**
	 * Returns the current state of the auto commit flag
	 * 
	 * @return Current state of the auto commit flag
	 * 
	 * @throws Exception
	 */
	public abstract boolean isAutoCommit() throws Exception;

	/**
	 * Sets the auto commit flag
	 * 
	 * @param autoCommit - new state for the auto commit flag
	 * 
	 * @throws Exception
	 */
	public abstract void setAutoCommit( boolean autoCommit ) throws Exception;
	
	/**
	 * Commits the current transaction.
	 * 
	 * @throws Exception
	 */
	public abstract void commit() throws Exception;
	
	/**
	 * Rolls back all changes done to the underlaying data
	 * 
	 * @throws Exception
	 */
	public abstract void rollback() throws Exception;
	
	/**
	 * Tests the data source batching support.
	 * 
	 * @return - <code>true</code> if the data source supports batched updates
	 * 
	 * @throws Exception
	 */
	public abstract boolean supportsBatching() throws Exception;
	
	/**
	 * Returns the data source type: e.g. 'oracle' for Oracle Database.
	 *  
	 * @return The data source type.
	 */
	public String getType()
	{
		return this.dataSourceType;
	}

	/**
	 * Returns the useBatchingWhenSupported.
	 *
	 * @return Returns the useBatchingWhenSupported.
	 */
	public boolean useBatchingWhenSupported()
	{
		return useBatchingWhenSupported;
	}

	/**
	 * Sets the useBatchingWhenSupported.
	 *
	 * @param useBatchingWhenSupported The useBatchingWhenSupported to set.
	 */
	public void enableBatchingWhenSupported(boolean useBatchingWhenSupported)
	{
		this.useBatchingWhenSupported = useBatchingWhenSupported;
	}
	
	
}
